
import collections as col_module
import testwrapper as test_module

from keyedset import *


Person = col_module.namedtuple("Person", "id, name, dob, contact")
InvalidPerson = col_module.namedtuple("Person", "key, name, dob, contact")

class TestKeyedSet(test_module.TestCase):

    def setup(self):
        self.data = [
                Person(1, "Bob", "1/1/1968", "714-555-2391"),
                Person(2, "Julius", "3/15", "Rome"),
                ]
        self.repeatsame = [
                Person(1, "Bob", "1/1/1968", "714-555-2391"),
                Person(2, "Julius", "3/15", "Rome"),
                Person(2, "Julius", "3/15", "Rome"),
                ]
        self.repeatdifferent = [
                Person(1, "Bob", "1/1/1968", "714-555-2391"),
                Person(2, "Julius", "3/15", "Rome"),
                Person(2, "Bob", "1/1/1968", "714-555-2391"),
                ]
        self.invalid = [
                InvalidPerson(1, "Bob", "1/1/1968", "714-555-2391"),
                InvalidPerson(2, "Julius", "3/15", "Rome"),
                ]

    def teardown(self):
        pass

    def test_init_empty(self):
        ks = KeyedSet()

    def test_init_valid(self):
        ks = KeyedSet(self.data)

    def test_init_valid_repeat_same(self):
        with self.assert_raises(KeyError):
            ks = KeyedSet(self.repeatsame)

    def test_init_valid_repeat_different(self):
        with self.assert_raises(KeyError):
            ks = KeyedSet(self.repeatdifferent)

    def test_init_invalid(self):
        with self.assert_raises(ValueError):
            ks = KeyedSet(self.invalid)

    def test_len_empty(self):
        ks = KeyedSet()
        self.assert_equal(len(ks), 0)

    def test_len_valid(self):
        ks = KeyedSet(self.data)
        self.assert_equal(len(ks), len(self.data))

    def test_iter_empty(self):
        ks = KeyedSet()
        for item in ks:
            self.fail("Should not have iterated.")
            
    def test_iter_valid(self):
        ks = KeyedSet(self.data)
        keys = []
        for item in ks:
            keys.append(ks._get_key(item))
        keys.sort()
        self.assert_equal(keys, [1,2])
            
    def test_contains_invalid(self):
        ks = KeyedSet()
        with self.assert_raises(ValueError):
            InvalidPerson(1, "Bob", "1/1/1968", "714-555-2391") in ks

    def test_contains_empty(self):
        ks = KeyedSet()
        self.assert_false(Person(1, "Bob", "1/1/1968", "714-555-2391") in ks)

    def test_contains_valid_found_same(self):
        ks = KeyedSet(self.data)
        self.assert_true(Person(1, "Bob", "1/1/1968", "714-555-2391") in ks)

    @test_module.expected_failure # still got to figure out if this should be the behavior
    def test_contains_valid_found_different(self):
        ks = KeyedSet(self.data)
        with self.assert_raises(ValueError):
            self.assert_true(Person(2, "Bob", "1/1/1968", "714-555-2391") in ks)

    def test_contains_valid_not_found(self):
        ks = KeyedSet(self.data)
        self.assert_false(Person(4, "Bob", "1/1/1968", "714-555-2391") in ks)

    def test_contains_missing_value(self):
        ks = KeyedSet()
        ks._dict[1] = None
        with self.assert_raises(MissingValueError):
            Person(1, "Bob", "1/1/1968", "714-555-2391") in ks

    def test_getitem_empty(self):
        ks = KeyedSet()
        with self.assert_raises(KeyError):
            ks[1]

    def test_getitem_found(self):
        ks = KeyedSet(self.data)
        ks[1]

    def test_getitem_not_found(self):
        ks = KeyedSet(self.data)
        with self.assert_raises(KeyError):
            ks[4]

    def test_get_found(self):
        ks = KeyedSet(self.data)
        self.assert_equal(ks[1], ks.get(1))

    def test_get_not_found(self):
        ks = KeyedSet(self.data)
        self.assert_is_none(ks.get(4))

    def test_keys_empty(self):
        ks = KeyedSet()
        self.assert_equal(ks.keys(), ())

    def test_keys_valid(self):
        ks = KeyedSet(self.data)
        self.assert_equal(ks.keys(), (1, 2))

    def test_one_empty(self):
        ks = KeyedSet()
        with self.assert_raises(KeyError):
            ks.one()

    def test_one_valid(self):
        ks = KeyedSet(self.data)
        self.assert_true(ks.one() in ks)


class TestMutableKeyedSet(test_module.TestCase):

    def setup(self):
        self.one = Person(0, "Bob", "1/1/1968", "714-555-2391")
        self.badone =  InvalidPerson(0, "Bob", "1/1/1968", "714-555-2391"),
        self.data = [
                Person(1, "Bob", "1/1/1968", "714-555-2391"),
                Person(2, "Julius", "3/15", "Rome"),
                ]
        self.repeatsame = [
                Person(1, "Bob", "1/1/1968", "714-555-2391"),
                Person(2, "Julius", "3/15", "Rome"),
                Person(2, "Julius", "3/15", "Rome"),
                ]
        self.repeatdifferent = [
                Person(1, "Bob", "1/1/1968", "714-555-2391"),
                Person(2, "Julius", "3/15", "Rome"),
                Person(2, "Bob", "1/1/1968", "714-555-2391"),
                ]
        self.invalid = [
                InvalidPerson(1, "Bob", "1/1/1968", "714-555-2391"),
                InvalidPerson(2, "Julius", "3/15", "Rome"),
                ]

    def teardown(self):
        pass

    def test_add_empty(self):
        ks = MutableKeyedSet()
        ks.add(self.one)
        self.assert_true(self.one in ks)
        self.assert_equal(len(ks), 1)

    def test_add_valid(self):
        ks = MutableKeyedSet(self.data)
        ks.add(self.one)
        self.assert_true(self.one in ks)
        self.assert_equal(len(ks), len(self.data)+1)

    def test_add_already_there(self):
        ks = MutableKeyedSet(self.data)
        with self.assert_raises(KeyError):
            ks.add(self.data[0])

    def test_add_invalid(self):
        ks = MutableKeyedSet(self.data)
        with self.assert_raises(ValueError):
            ks.add(self.badone)

    def test_discard_empty(self):
        ks = MutableKeyedSet()
        with self.assert_raises(KeyError):
            ks.discard(self.one)

    def test_discard_valid_found(self):
        ks = MutableKeyedSet(self.data)
        ks.discard(self.data[0])
        self.assert_false(self.data[0] in ks)
        self.assert_equal(len(ks), len(self.data)-1)

    def test_discard_valid_not_found(self):
        ks = MutableKeyedSet(self.data)
        with self.assert_raises(KeyError):
            ks.discard(self.one)
        self.assert_equal(len(ks), len(self.data))

    def test_delitem_empty(self):
        ks = MutableKeyedSet()
        with self.assert_raises(KeyError):
            del ks[0]

    def test_delitem_valid_found(self):
        ks = MutableKeyedSet(self.data)
        del ks[1]
        self.assert_false(self.data[0] in ks)
        self.assert_equal(len(ks), len(self.data)-1)

    def test_delitem_valid_not_found(self):
        ks = MutableKeyedSet(self.data)
        with self.assert_raises(KeyError):
            del ks[0]
        self.assert_equal(len(ks), len(self.data))

    def test_pop_empty(self):
        ks = MutableKeyedSet()
        with self.assert_raises(KeyError):
            ks.pop()

    def test_pop_valid(self):
        ks = MutableKeyedSet(self.data)
        item = ks.pop()
        self.assert_true(item in self.data)
        self.assert_false(item in ks)
        self.assert_equal(len(ks), len(self.data)-1)


class TestLazyKeyedSet(test_module.TestCase):
    pass


if __name__ == '__main__':
    test_module.main(verbosity=2)

